﻿using ApproveFlowEngine.EntityFrameworkCoreSplitTable.AbpCore;
using ApproveFlowEngine.EntityFrameworkCoreSplitTable.EFCore.Core;
using ApproveFlowEngine.Split;

using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;

using Volo.Abp.EntityFrameworkCore;
using Volo.Abp.Modularity;

namespace ApproveFlowEngine.EntityFrameworkCoreSplitTable
{
    public class ApproveFlowEngineEntityFrameworkCoreSplitTableModel : AbpModule
    {
        public override void PreConfigureServices(ServiceConfigurationContext context)
        {
            //ApproveFlowEngineEfCoreEntityExtensionMappings.Configure();
        }

        public override void ConfigureServices(ServiceConfigurationContext context)
        {
            var baseType = typeof(SplitDbContext);
            var dbType = typeof(DbSet<>);
            var assemblies = AppDomain.CurrentDomain.GetAssemblies()
                                                    .Where(c => !(c.FullName.StartsWith("Microsoft")
                                                    || c.FullName.StartsWith("System")
                                                    || c.FullName.StartsWith("Volo")
                                                    || c.FullName.StartsWith("Serilog")));

            var types = assemblies.SelectMany(c => c.ExportedTypes)
                                  .Where(c => c.IsAssignableTo(baseType) && !c.IsAbstract && !c.IsInterface);

            foreach (var item in types)
            {
                var iManagerService = typeof(ISplitTableManager<>);
                iManagerService = iManagerService.MakeGenericType(item);
                var managerImplementService = typeof(SplitTableManager<>);
                managerImplementService = managerImplementService.MakeGenericType(item);
                context.Services.AddTransient(iManagerService, managerImplementService);

                var dbProp = item.GetProperties()
                                 .Where(c => c.PropertyType.IsGenericType && c.PropertyType.GetGenericTypeDefinition() == dbType)
                                 .Select(c => c.PropertyType);

                foreach (var prop in dbProp)
                {
                    var genericType = prop.GenericTypeArguments.FirstOrDefault();
                    if (genericType.IsAssignableTo<ISplitTable>())
                    {
                        var serviceType = typeof(ISplitRepository<>);
                        serviceType = serviceType.MakeGenericType(genericType);

                        var implementationType = typeof(SplitRepository<,>);
                        implementationType = implementationType.MakeGenericType(item, genericType);

                        context.Services.AddTransient(serviceType, implementationType);
                    }
                }
            }
            context.Services.Replace(new ServiceDescriptor(typeof(IDbContextProvider<>), typeof(SplitRepositoryProvider<>), ServiceLifetime.Scoped));
        }
    }
}